package com.urban.pooling.controller.api;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.urban.pooling.domain.GeoPoint;
import com.urban.pooling.domain.Route;
import com.urban.pooling.domain.User;
import com.urban.pooling.dto.RouteDto;
import com.urban.pooling.service.RouteService;
import com.urban.pooling.service.UserService;
import com.urban.pooling.util.AppUtil;
import com.urban.pooling.util.DomainUtil;

@Controller
@RequestMapping("/api/routes")
public class RouteApiController {
	private static final Logger LOG = LoggerFactory.getLogger(RouteApiController.class);

	@Autowired
	private RouteService routeService;

	@Autowired
	private UserService userService;

	private Gson gson = new GsonBuilder().setDateFormat(AppUtil.DATE_TIME_FORMAT).create();

	@Transactional
	@RequestMapping(value = { "", "/" }, method = RequestMethod.GET, produces = { "application/json; charset=UTF-8" })
	public @ResponseBody
	String getAllRoutes(@RequestParam(value="username", required=false) String username) {
		List<RouteDto> routeDtos = new ArrayList<RouteDto>();
		Iterable<Route> routes = null;
		if (username == null || username.equals("")) {
			routes = routeService.findAll();
		} else {
			routes = routeService.findByUsername(username);
		}
		for (Route route : routes) {
			routeDtos.add(DomainUtil.createDto(route));
		}

		return gson.toJson(routeDtos);
	}


	@RequestMapping(value = { "/{id}" }, method = RequestMethod.GET, produces = { "application/json; charset=UTF-8" })
	public @ResponseBody
	String getRoute(@PathVariable("id") Integer routeId) {
		String routeJson = null;
		Route route = routeService.findOne(routeId);
		if (route != null) {
			RouteDto routeDto = DomainUtil.createDto(route);
			routeJson = gson.toJson(routeDto);
		}
		LOG.debug(route.toString());
		return routeJson;
	}

	@RequestMapping(value = { "", "/" }, method = RequestMethod.POST)
	public @ResponseBody
	String saveRoute(@RequestBody String routeJson) {
		LOG.debug("Save route :" + routeJson);
		RouteDto routeDto = gson.fromJson(routeJson, RouteDto.class);
		User driver = userService.find(routeDto.getDriverId());
		routeService.add(DomainUtil.createRoute(routeDto, driver));
		return "{}";// TODO
	}

	/**
	 * 
	 * @param lat1
	 * @param lng1
	 * @param lat2
	 * @param lng2
	 * @param lowerStartDate
	 * @param availableSeats
	 * @param radius
	 *            in km
	 * @return
	 */
	@RequestMapping(value = "/search", method = RequestMethod.GET, produces = { "application/json; charset=UTF-8" })
	public @ResponseBody
	String searchRoutes(
			@RequestParam(value = "startLat", required = true) double lat1,
			@RequestParam(value = "startLng", required = true) double lng1,
			@RequestParam(value = "destLat", required = true) double lat2,
			@RequestParam(value = "destLng", required = true) double lng2,
			@RequestParam(value = "lowerStartDate", required = false) @DateTimeFormat(pattern = AppUtil.DATE_TIME_FORMAT) Date lowerStartDate,
			@RequestParam(value = "upperStartDate", required = false) @DateTimeFormat(pattern = AppUtil.DATE_TIME_FORMAT) Date upperStartDate,
			@RequestParam(value = "availableSeats", required = false, defaultValue = "1") int availableSeats,
			@RequestParam(value = "radius", required = false, defaultValue = "1") float radius) {
		GeoPoint startPoint = new GeoPoint(lat1, lng1);
		GeoPoint destPoint = new GeoPoint(lat2, lng2);
		if (lowerStartDate == null) {
			lowerStartDate = new Date();
		}

		if (upperStartDate == null) {
			Calendar cal = Calendar.getInstance();
			cal.add(Calendar.YEAR, 1000);
			upperStartDate = cal.getTime();
		}

		List<RouteDto> routeDtos = new ArrayList<RouteDto>();
		Iterable<Route> routes = routeService.search(startPoint, destPoint, lowerStartDate, upperStartDate,
				availableSeats, radius);
		for (Route route : routes) {
			routeDtos.add(DomainUtil.createDto(route));
		}

		return gson.toJson(routeDtos);
	}
}
